package com.itany.shop.util;

import com.itany.shop.exception.DataAccessException;

import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author MissChen
 * @date 2024年03月28日 16:47
 */
public class JDBCTemplate<T>{

    /**
     * 执行一个DML操作，即:insert、delete、update
     * 对于增删改操作，使用 ps.executeUpdate()执行sql
     * 对于整个方法而言，sql与参数不一致，其他代码几乎相同
     * 可以将sql和参数设置为当前模板方法的参数
     * 由于参数不一致，可以设置为不定长参数
     * @param sql 执行的sql语句
     * @param params 执行SQL所需要的参数
     */
    public void update(String sql,Object... params){
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            conn=JDBCUtil.getConnection();
            ps=conn.prepareStatement(sql);
           // 可变长参数用于接收实际的参数
           for(int i=0;i<params.length;i++){
                //取出当前遍历的参数
               Object param=params[i];
               if(param instanceof String){
                   ps.setString(i+1, (String) param);
               }else if(param instanceof Integer){
                   ps.setInt(i+1, (Integer) param);
               }else if(param instanceof Double){
                   ps.setDouble(i+1, (Double) param);
               }else{
                   ps.setObject(i+1,param);
               }
           }
           //执行DML操作
           ps.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {

            //在业务层的事务操作中需要使用Connection，此时这个地方不需要释放Connection
            JDBCUtil.close(null,ps,null);
        }
    }

    /**
     * 执行一个查询操作
     * @param sql 执行的sql语句
     * @param rm  行映射，将查询的结构映射成具体的Java对象
     * @param params 执行SQL所需要的参数
     * @return
     */
    public List<T> query(String sql,RowMapper rm,Object... params){
        Connection conn=null;
        ResultSet rs=null;
        PreparedStatement ps=null;
        List<T> list=new ArrayList<>();
        try {
            conn=JDBCUtil.getConnection();
            ps=conn.prepareStatement(sql);
            // 可变长参数用于接收实际的参数
            for(int i=0;i<params.length;i++) {
                //取出当前遍历的参数
                Object param = params[i];
                if (param instanceof String) {
                    ps.setString(i + 1, (String) param);
                } else if (param instanceof Integer) {
                    ps.setInt(i + 1, (Integer) param);
                } else if (param instanceof Double) {
                    ps.setDouble(i + 1, (Double) param);
                } else {
                    ps.setObject(i + 1, param);
                }
            }

            //执行查询操作
            rs=ps.executeQuery();
            while(rs.next()){
                T t= (T) rm.mapRow(rs);
                list.add(t);
            }
            return list;

        } catch (SQLException e) {
           throw new DataAccessException("数据库访问异常");
        }finally {
            JDBCUtil.close(null,ps,rs);
        }

    }


    public void insertReturnPrimaryKey(PreparedStatementCreator psc,KeyHolder keyHolder){
        Connection conn=null;
        ResultSet rs=null;
        PreparedStatement ps=null;

        try {
            conn=JDBCUtil.getConnection();

            //调用者在调用方法的时候做一个具体的视线
            // 在实现的时候，会提供构建状态集所需要的sql与参数
            ps=psc.createPreparedStatement(conn);
            ps.executeUpdate();

            //添加到数据库中自动生成对应的主键
            //获取生成的主键的值
            rs=ps.getGeneratedKeys();


            //准备一个集合，用于存储所有自动生成的主键的值
            List<Integer> list=new ArrayList<>();

            //通过结果集元素数据获取生成的主键值
            ResultSetMetaData rsmd=rs.getMetaData();

            //获取生成的列的总数
            int columnCount=rsmd.getColumnCount();

            if(rs.next()){
                //将主键值添加到list中去
                for(int i=1;i<=columnCount;i++){
                    list.add(rs.getInt(i));
                }
            }
            keyHolder.setKeyList(list);

        } catch (SQLException e) {
            throw new DataAccessException("数据库访问异常");
        }finally {
            JDBCUtil.close(null,ps,rs);
        }

    }




}
